package biz.datalk.industrialland.common.config;

import biz.datalk.commons.utils.BasicParserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.core.env.Environment;

import java.io.Serializable;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * jwt加解密key单例
 * @author tarofang@163.com
 * @date 2019-09-11
 */
@Slf4j
public class JwtCryptoCfg implements Serializable {
    private static final long serialVersionUID = 6622697122074714536L;
    private boolean init = false;
    private JwtCryptoCfg(){
        defaultInit();
    }
    private static class JwtCryptoCfgInner {
        private static final JwtCryptoCfg INSTANCE = new JwtCryptoCfg();
    }
    /** 解决反序列化后不是同一个对象 */
    protected Object readResolve() {
        return JwtCryptoCfgInner.INSTANCE;
    }
    public static JwtCryptoCfg getInstance() {
        return JwtCryptoCfgInner.INSTANCE;
    }

    //==============================================================================
    /** 初始化方法 */
    private void defaultInit() {
        log.debug("JwtCryptoCfg defaultInit into");
        if (this.init) {
            return;
        }
        try {
            this.aesKey = "datalkYdwxSecret";
            this.rsaPrivateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJyd4kzfiDgLD1CDu9rnokwp9IQ3y5jLJSQWIY8bwdrKcxheSJpgj7+5UM6t37gg1sTJHtH6AfJdOdrWp5s9xPy5qjPr5+1cAfboywjlcE9oclGsRPpkM4V1eGGkGRro1+y0Z6jPuYKdPYIRm6T58G8FPJqaOj6Vha5a8CbYxqwRAgMBAAECgYAEP7xN/ZqCerpVot1L2RDsJA9ALwtU/93oFrmeWlBuESQCOzyZA5mix/JLSShSpIFvIU22wKOg4aqaJ0ywx4I6lgmw23xnHnvdlcKng6nLHpwe64vXXCwh1ev/gL1FUgRRDF0Sm+dP5ZzBiJ8Xcm1TQN62c7fn5EUGIhz01o2EAQJBAOjpQiwxLqAwTzW72KpT9oTae/3AgZcewm3W/DbiBEaSHTZ+4X8XGQUBNKE52/K99RXAcy+TCdDeh0ImY8ZGQrECQQCsJHNzgolVKXlkH2s3wTzmAZXNOFGi0tEh2++LDVM1eX2ctDql4hTM1sYvgAL6amMogbkQeAlCpjsXMQEOIZdhAkBTrSG58L14jYKXonIX12x0lG4BXzzvhvyBK8CXEyJIHExkfLcUyr6RXrqCxd+wWPCJLQf06pWXNatQZ6xm2m0xAkBh2l6efMegV3EfzxRdn0UE4kXLYIZXbktfWexzOOHh9evHllP4U+nK/xOtkLEgtDUlo4gVqoZpEqFob3zQEZxBAkAjC8n4h+XCUEybk9ZxLlkxGndR/v6LX4YUjvGWJ5YqPc8+bArIlCA+LECN1zaHoU9SX1teslENDyBOZGya84br";
            this.rsaPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcneJM34g4Cw9Qg7va56JMKfSEN8uYyyUkFiGPG8HaynMYXkiaYI+/uVDOrd+4INbEyR7R+gHyXTna1qebPcT8uaoz6+ftXAH26MsI5XBPaHJRrET6ZDOFdXhhpBka6NfstGeoz7mCnT2CEZuk+fBvBTyamjo+lYWuWvAm2MasEQIDAQAB";
            this.expire = 30 * 60L;
        } finally {
            log.debug("JwtCryptoCfg defaultInit out");
        }
    }

    public void init(Environment env) {
        log.debug("JwtCryptoCfg into");
        if (this.init) {
            log.warn("JwtCryptoCfg has been initialized");
            return;
        }
        try {
            String aesKey = env.getProperty("datalk.jwt.aeskey");
            String rsaPrivateKey = env.getProperty("datalk.jwt.rsakey.private");
            String rsaPublicKey = env.getProperty("datalk.jwt.rsakey.public");
            String expire = env.getProperty("datalk.jwt.expire");

            this.aesKey = StringUtils.isBlank(aesKey) ? this.aesKey : aesKey.trim();
            this.rsaPrivateKey = StringUtils.isBlank(rsaPrivateKey) ? this.rsaPrivateKey : rsaPrivateKey.trim();;
            this.rsaPublicKey = StringUtils.isBlank(rsaPublicKey) ? this.rsaPublicKey : rsaPublicKey.trim();;
            this.expire = BasicParserUtils.parseLong(expire, this.expire);

            this.init = true;
        } finally {
            log.debug("JwtCryptoCfg out");
        }
    }

    public KeyPair genKeyPair() {
        try {
            if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
                Security.addProvider(new BouncyCastleProvider());
            }

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            // 解析私钥
            byte[] privateKeyBytes = Base64.decodeBase64(this.rsaPrivateKey);
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

            // 解析公钥
            byte[] publicKeyBytes = Base64.decodeBase64(this.rsaPublicKey);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
            PublicKey pubKey = keyFactory.generatePublic(keySpec);

            return new KeyPair(pubKey, priKey);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    //字段
    private String aesKey;
    private String rsaPublicKey;
    private String rsaPrivateKey;

    private long expire;

    //getter
    public String getAesKey() {
        return aesKey;
    }

    public String getRsaPublicKey() {
        return rsaPublicKey;
    }

    public String getRsaPrivateKey() {
        return rsaPrivateKey;
    }

    public long getExpire() {
        return expire;
    }
    public long getExpireMillis() {
        return expire * 1000;
    }
}
